package com.lvy.hczn.transmit.service.impl;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lvy.hczn.front.common.constant.Constants;
import com.lvy.hczn.front.common.constant.MqConstants;
import com.lvy.hczn.front.common.core.domain.BaseModel;
import com.lvy.hczn.front.common.core.domain.entity.SysDictData;
import com.lvy.hczn.front.common.core.domain.entity.SysUser;
import com.lvy.hczn.front.common.core.redis.RedisCache;
import com.lvy.hczn.front.common.core.text.Convert;
import com.lvy.hczn.front.common.exception.ServiceException;
import com.lvy.hczn.front.common.exception.UtilException;
import com.lvy.hczn.front.common.utils.DictUtils;
import com.lvy.hczn.front.common.utils.ShiroUtils;
import com.lvy.hczn.front.common.utils.StringUtils;
import com.lvy.hczn.front.common.utils.bean.BeanValidators;
import com.lvy.hczn.front.common.utils.security.Md5Utils;
import com.lvy.hczn.front.system.domain.business.*;
import com.lvy.hczn.front.system.domain.transmit.SupplierBoxBatchNumber;
import com.lvy.hczn.front.system.domain.transmit.dto.SupplierBoxBatchNumberExport;
import com.lvy.hczn.front.system.service.GoodsBoxSpecService;
import com.lvy.hczn.front.system.service.WarehouseService;
import com.lvy.hczn.mq.rocket.ParamInfo;
import com.lvy.hczn.mq.rocket.ProducerUtil;
import com.lvy.hczn.transmit.common.ConstantTransmit;
import com.lvy.hczn.transmit.domain.dto.cteck.BoxNew;
import com.lvy.hczn.transmit.domain.dto.cteck.Container;
import com.lvy.hczn.transmit.mapper.GoodsBoxMapper;
import com.lvy.hczn.transmit.service.ConsumeService;
import com.lvy.hczn.transmit.service.ContainerService;
import com.lvy.hczn.transmit.service.GoodsBoxService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.swing.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class GoodsBoxServiceImpl extends ServiceImpl<GoodsBoxMapper, GoodsBox> implements GoodsBoxService {

    @Autowired
    private GoodsBoxMapper goodsBoxMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private GoodsBoxSpecService goodsBoxSpecService;

    @Autowired
    private WarehouseService warehouseService;

    @Autowired
    private ProducerUtil producerUtil;

    @Autowired
    private ContainerService containerService;

    @Autowired
    private ConsumeService consumeService;

    @Override
    public List<GoodsBox> selectBoxlist(GoodsBox goodsBox) {
        goodsBox.setCreateBy(ShiroUtils.getLoginName());
        return selectGoodsBoxList(goodsBox);
    }

    /**
     * 新生产的货箱录入
     *
     * @param goodsBox
     * @return
     * @author yw
     * @date 2023-05-16 20:40:55
     */
    @Override
    public int saveData(GoodsBox goodsBox) {
        //todo 写了两套，原先是数据中心初始化货箱，即供应商批量导入，现在仓库也可以新货箱称重入新货箱，后续调整为一套，唯一区别是此处的标准重量是统一的，仓库的标准重量是实际称重的
        List<SysDictData> list = DictUtils.getDictCache(ConstantTransmit.BOX_TYPE_ERROR_RANGE);
        List<SysDictData> boxSizeList = DictUtils.getDictCache(ConstantTransmit.BOX_SIZE_INFO);
        LinkedHashMap<String, List<SysDictData>> boxCodeMap = new LinkedHashMap<>();
        if (boxSizeList != null && !boxSizeList.isEmpty()) {
            boxCodeMap = boxSizeList.stream().collect(Collectors.groupingBy(SysDictData::getDictValue, LinkedHashMap::new, Collectors.toList()));
        }
        if (list != null && !list.isEmpty()) {
            for (SysDictData sysDictData : list) {
                if (goodsBox.getType() == ConstantTransmit.BOX_TYPE_BIG) {
                    //大货箱
                    if (sysDictData.getDictLabel().equals(ConstantTransmit.BOX_ERROR_MAX_BIG)) {
                        goodsBox.setErrorMax(new BigDecimal(sysDictData.getDictValue()));
                    } else if (sysDictData.getDictLabel().equals(ConstantTransmit.BOX_ERROR_MAX_SMALL)) {
                        goodsBox.setErrorMin(new BigDecimal(sysDictData.getDictValue()));
                    }
                    if (boxCodeMap.containsKey(String.valueOf(ConstantTransmit.BOX_TYPE_BIG))) {
                        SysDictData boxSizeData = boxCodeMap.get(String.valueOf(ConstantTransmit.BOX_TYPE_BIG)).get(0);
                        if (boxSizeData.getRemark() != null && NumberUtil.isInteger(boxSizeData.getRemark()) && goodsBox.getBoxStandardWeight() == null) {
                            goodsBox.setBoxStandardWeight(new BigDecimal(boxSizeData.getRemark()));
                        }
                    }
                } else if (goodsBox.getType() == ConstantTransmit.BOX_TYPE_SMALL) {
                    //小货箱
                    if (sysDictData.getDictLabel().equals(ConstantTransmit.BOX_ERROR_MIN_BIG)) {
                        goodsBox.setErrorMax(new BigDecimal(sysDictData.getDictValue()));
                    } else if (sysDictData.getDictLabel().equals(ConstantTransmit.BOX_ERROR_MIN_SMALL)) {
                        goodsBox.setErrorMin(new BigDecimal(sysDictData.getDictValue()));
                    }
                    if (boxCodeMap.containsKey(String.valueOf(ConstantTransmit.BOX_TYPE_SMALL))) {
                        SysDictData boxSizeData = boxCodeMap.get(String.valueOf(ConstantTransmit.BOX_TYPE_SMALL)).get(0);
                        if (boxSizeData.getRemark() != null && NumberUtil.isInteger(boxSizeData.getRemark()) && goodsBox.getBoxStandardWeight() == null) {
                            goodsBox.setBoxStandardWeight(new BigDecimal(boxSizeData.getRemark()));
                        }
                    }
                }
            }
        }
        if (StrUtil.isEmpty(goodsBox.getWarehouseId())) {
            goodsBox.setWarehouseId("0");
        }
        goodsBox.setWarehousingEntryTime(LocalDateTime.now());
        goodsBox.setInspectType("0");
        goodsBox.setBoxType(ConstantTransmit.GOODS_BOX_TYPE_ZERO);
        return goodsBoxMapper.insert(goodsBox);
    }

    @Override
    public List<String> generateBoxNo(String prefix) {
        if (StrUtil.isEmpty(prefix)) {
            throw new UtilException("前缀为空");
        }
        return null;
    }

    /**
     * 调拨/配送单提前录入货箱到仓库
     *
     * @param list
     * @return void
     * @author yw
     * @date 2023-06-25 19:50:37
     */
    @Override
    public void syncToWms(List<GoodsBox> list, String warehouseCode, String topic) {
        List<GoodsBox> goodsBoxList = new ArrayList<>();
        LinkedHashMap<String, List<GoodsBox>> goodsBoxMap = list.stream().collect(Collectors.groupingBy(GoodsBox::getBoxCode, LinkedHashMap::new, Collectors.toList()));
        goodsBoxMap.forEach((k, v) -> {
            if (!v.isEmpty()) {
                GoodsBox goodsBox = v.get(0);
                GoodsBoxSpec goodsBoxSpec = goodsBoxSpecService.getById(goodsBox.getGoodsBoxSpecId());
                GoodsBox goodsBoxInfo = super.getOne(Wrappers.<GoodsBox>lambdaQuery().eq(GoodsBox::getBoxCode, goodsBox.getBoxCode()));
                if (goodsBoxSpec != null && goodsBoxInfo != null) {
//                    goodsBox.setType(Integer.valueOf(goodsBoxSpec.getSpecCode()));
                    goodsBox.setInspectType("0");
                    goodsBox.setWarehousingEntryTime(LocalDateTime.now());
                    goodsBox.setBoxType(Constants.GOODS_BOX_TYPE_SIX);
                    goodsBox.setStatus(Constants.GOODS_BOX_STATE_SIX);
                    goodsBox.setErrorMax(goodsBoxInfo.getErrorMax());
                    goodsBox.setErrorMin(goodsBoxInfo.getErrorMin());
//                    goodsBox.setWeight(BigDecimal.ZERO);
                    goodsBox.setVolume(BigDecimal.ZERO);
                    goodsBox.setCreateBy(goodsBoxInfo.getCreateBy());
                    goodsBox.setBoxStandardWeight(goodsBoxInfo.getBoxStandardWeight());
                    goodsBox.setVolume(goodsBoxSpec.getVolume());
                    goodsBoxList.add(goodsBox);
                }
            }
        });

        if (!goodsBoxList.isEmpty()) {
            String tag = warehouseCode + "_" + MqConstants.TOPIC_WAREHOUSE_CIRCULATION_BOX;
            ParamInfo<GoodsBox> paramInfo = new ParamInfo<>();
            paramInfo.setList(goodsBoxList);
            try {
                producerUtil.sendAsyncMsg(topic, tag, JSON.toJSONString(paramInfo).getBytes(StandardCharsets.UTF_8), IdUtil.fastSimpleUUID());
            } catch (Exception e) {
                throw new UtilException("货箱转发异常");
            }
        }
    }

    /**
     * 查询货箱信息
     *
     * @param id 货箱信息主键
     * @return 货箱信息
     */
    @Override
    public GoodsBox selectGoodsBoxById(String id) {
        return goodsBoxMapper.selectById(id);
    }

    /**
     * 查询货箱信息列表
     *
     * @param goodsBox 货箱信息
     * @return 货箱信息
     */
    @Override
    public List<GoodsBox> selectGoodsBoxList(GoodsBox goodsBox) {
        return goodsBoxMapper.selectGoodsBoxList(goodsBox);
    }

    /**
     * 新增货箱信息
     *
     * @param goodsBox 货箱信息
     * @return 结果
     */
    @Override
    public int insertGoodsBox(GoodsBox goodsBox) {
        return goodsBoxMapper.insert(goodsBox);
    }

    /**
     * 修改货箱信息
     *
     * @param goodsBox 货箱信息
     * @return 结果
     */
    @Override
    public int updateGoodsBox(GoodsBox goodsBox) {
        return goodsBoxMapper.updateById(goodsBox);
    }

    /**
     * 批量删除货箱信息
     *
     * @param ids 需要删除的货箱信息主键
     * @return 结果
     */
    @Override
    public int deleteGoodsBoxByIds(String ids) {
        if (StrUtil.isEmpty(ids)) {
            throw new UtilException("ID为空");
        }
        String[] arrId = Convert.toStrArray(ids);
        for (String id : arrId) {
            super.removeById(id);
        }
        return arrId.length;
    }

    /**
     * 删除货箱信息信息
     *
     * @param id 货箱信息主键
     * @return 结果
     */
    @Override
    public int deleteGoodsBoxById(String id) {
        return goodsBoxMapper.deleteById(id);
    }

    /**
     * 生成货箱编码时，初始化货箱数据
     *
     * @param exports
     * @param supplierBoxBatchNumber
     * @param sysUser
     * @return void
     * @author yw
     * @date 2023-09-07 19:53:20
     */
    @Override
    public void initGoodsBox(List<SupplierBoxBatchNumberExport> exports, SupplierBoxBatchNumber supplierBoxBatchNumber, SysUser sysUser) {
        if (exports != null && !exports.isEmpty()) {
            for (SupplierBoxBatchNumberExport export : exports) {
                GoodsBox goodsBox = new GoodsBox();
                goodsBox.setGoodsBoxSpecId(supplierBoxBatchNumber.getGoodsBoxSpecId());
                goodsBox.setBoxCode(export.getBoxNumber());
                goodsBox.setCreateBy(sysUser.getLoginName());
                goodsBox.setUpdateBy(sysUser.getLoginName());
                goodsBox.setStatus(ConstantTransmit.GOODS_BOX_STATE_FOUR);
                List<GoodsBox> goodsBoxList = new ArrayList<>();
                goodsBoxList.add(goodsBox);
                this.importGoodsBox(goodsBoxList, false, sysUser.getLoginName(), sysUser, false);
            }
        }
    }

    /**
     * 货箱生产商导入货箱
     *
     * @param goodsBoxList
     * @param isUpdateSupport
     * @param operName
     * @param sysUser
     * @param syncToPlatform  生成货箱编号的数据初始化，不生发送到平台，用户导入的发送到平台
     * @return java.lang.String
     * @author yw
     * @date 2023-09-07 19:34:15
     */
    @Override
    public String importGoodsBox(List<GoodsBox> goodsBoxList, Boolean isUpdateSupport, String operName, SysUser sysUser, boolean syncToPlatform) {

        if (StringUtils.isNull(goodsBoxList) || goodsBoxList.size() == 0) {
            throw new ServiceException("货箱数据不能为空！");
        }
        if (sysUser.getRemark().isEmpty()) {
            throw new ServiceException("用户未绑定仓库，请先完善");
        }
        Warehouse warehouse = warehouseService.getOne(Wrappers.<Warehouse>lambdaQuery().eq(Warehouse::getWarehouseCode, sysUser.getRemark()));
        if (warehouse == null) {
            throw new ServiceException("用户绑定的仓库信息不存在，请检查");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        String reg = DictUtils.getDictValue(Constants.SYS_DICT_BOX_CODE_REG, Constants.SYS_DICT_BOX_CODE_REG_INFO);
        List<GoodsBox> goodsBoxListCopy = new ArrayList<>();
        for (GoodsBox goodsBox : goodsBoxList) {
            try {
                if (StrUtil.isEmpty(goodsBox.getBoxCode())) {
                    throw new ServiceException("货箱编号列表有空值，请检查");
                }
                //正则表达式校验：前两位为大写字母，第三位为0或1，剩余九位为0-9的数字
                if (!goodsBox.getBoxCode().matches(reg)) {
                    throw new ServiceException("货箱编号" + goodsBox.getBoxCode() + "格式错误，请检查");
                }
                //取第三位的值，判断大小货箱
                goodsBox.setType(Integer.valueOf(goodsBox.getBoxCode().substring(2, 3)));
                goodsBox.setWarehouseId(warehouse.getId());
                goodsBox.setWarehouseCode(warehouse.getWarehouseCode());
                // 验证是否存在这个用户
                GoodsBox u = super.getOne(Wrappers.<GoodsBox>lambdaQuery().eq(GoodsBox::getBoxCode, goodsBox.getBoxCode()));
                if (StringUtils.isNull(u) && !syncToPlatform) {
                    //货箱供应商生成货箱编号的时候，进入
                    this.saveData(goodsBox);
                    successNum++;
//                    successMsg.append("<br/>" + successNum + "、货箱 " + goodsBox.getBoxCode() + " 导入成功");
                } else if (StringUtils.isNotNull(u) && syncToPlatform) {
                    //货箱供应商生产完后，页面导入做更新
                    goodsBox.setId(u.getId());
                    goodsBox.setStatus("");
                    if (super.updateById(goodsBox)) {
                        successNum++;
                        //货箱编号生成时，初始化数据，Status为空，货箱编号导入的时候，设置为异常货箱，这样就只发一次到平台
                        //不在货箱初始化的时候发的原因，在于生成一千个货箱编号，不代表会有一千个货箱
                        if (ConstantTransmit.GOODS_BOX_STATE_FOUR.equals(u.getStatus())) {
                            goodsBoxListCopy.add(u);
                        }
                    }
//                    successMsg.append("<br/>" + successNum + "、货箱 " + goodsBox.getBoxCode() + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、货箱 " + goodsBox.getBoxCode() + " 输入有误或已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、货箱 " + goodsBox.getBoxCode() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "数据已全部导入成功！共 " + successNum + " 条");
        }
        //新建货箱发送到平台
        if (syncToPlatform && !goodsBoxListCopy.isEmpty()) {
            ThreadUtil.execAsync(() -> {
                sendNewGoodsBoxInfo(goodsBoxListCopy);
            });
        }
        return successMsg.toString();
    }

    /**
     * 新增货箱发送到平台
     *
     * @param goodsBoxListCopy
     * @return void
     * @author yw
     * @date 2023-09-07 20:14:40
     */
    @Deprecated
    private void sendNewGoodsBox(List<GoodsBox> goodsBoxListCopy) {
        List<Container> containers = new ArrayList<>();
        goodsBoxListCopy.forEach(goodsBox -> {
            Warehouse warehouse = warehouseService.getById(goodsBox.getWarehouseId());
            if (warehouse != null) {
                Container container = new Container();
                container.setContainerCode(goodsBox.getBoxCode());
                container.setContainerId(goodsBox.getGoodsBoxSpecId());
                container.setContainerState(1);
                container.setRepId(warehouse.getWarehouseCode());
                if (StrUtil.isEmpty(goodsBox.getCreateBy())) {
                    container.setCreateUser("wms");
                } else {
                    container.setCreateUser(goodsBox.getCreateBy());
                }
                containers.add(container);
            } else {
                log.error("sendNewGoodsBox仓库不存在，仓库ID：{}", goodsBox.getWarehouseId());
            }

        });
        containerService.syncContainerToPlatForm(containers);
    }

    /**
     * 货箱生产商生产货箱同步
     *
     * @param goodsBoxListCopy
     * @return void
     * @author yw
     * @date 2023-12-16 16:57:21
     */
    @Override
    public void sendNewGoodsBoxInfo(List<GoodsBox> goodsBoxListCopy) {
        ParamInfo<WarehouseBoxEntry> info = new ParamInfo<>();
        Integer serviceType = com.lvy.hczn.front.common.constant.Constants.BOX_EMPTY_SERVICE_TYPE_IN;
        Integer overType = com.lvy.hczn.front.common.constant.Constants.BOX_EMPTY_OVER_TYPE_ONE;
        String boxEntryCode = IdUtil.getSnowflakeNextIdStr();
        List<WarehouseBoxEntry> list = new ArrayList<>();
        goodsBoxListCopy.forEach(goodsBox -> {
            Warehouse warehouse = warehouseService.getById(goodsBox.getWarehouseId());
            if (warehouse != null) {
                WarehouseBoxEntry warehouseBoxEntry = new WarehouseBoxEntry();
                warehouseBoxEntry.setBoxEntryCode(boxEntryCode);
                warehouseBoxEntry.setBoxCode(goodsBox.getBoxCode());
                warehouseBoxEntry.setWarehouseCode(warehouse.getWarehouseCode());
                warehouseBoxEntry.setType(serviceType);
                warehouseBoxEntry.setOverType(overType);
                warehouseBoxEntry.setBoxCode(goodsBox.getBoxCode());
                warehouseBoxEntry.setGoodsBoxSpecCode(goodsBox.getGoodsBoxSpecId());
                warehouseBoxEntry.setTotal(1);
                if (!StrUtil.isEmpty(goodsBox.getCreateBy())) {
                    warehouseBoxEntry.setBoxProducer(goodsBox.getCreateBy());
                    warehouseBoxEntry.setCreateBy(goodsBox.getCreateBy());
                } else {
                    warehouseBoxEntry.setBoxProducer("wms");
                    warehouseBoxEntry.setCreateBy("wms");
                }
                warehouseBoxEntry.setTreated(false);
                list.add(warehouseBoxEntry);
            } else {
                log.error("sendNewGoodsBoxInfo仓库不存在，仓库ID：{}", goodsBox.getWarehouseId());
            }
        });
        if (!list.isEmpty()) {
            info.setList(list);
            info.setWarehouseCode(list.get(0).getWarehouseCode());
            consumeService.syncEmptyBox(JSON.toJSONString(info));
        }
    }

    /**
     * 根据货箱编码查询货箱信息
     *
     * @param request
     * @param goodsBoxParamInfo
     * @return com.lvy.common.ParamInfo<com.lvy.hczn.transmit.domain.dto.cteck.BoxNew>
     * @author yw
     * @date 2023-12-16 17:00:27
     */
    @Override
    public ParamInfo<BoxNew> selectBoxSupplierByBoxCode(HttpServletRequest request, ParamInfo<GoodsBox> goodsBoxParamInfo) {
        if (goodsBoxParamInfo == null || goodsBoxParamInfo.getData() == null) {
            throw new UtilException("参数错误");
        }
        GoodsBox goodsBox = JSON.parseObject(JSON.toJSONString(goodsBoxParamInfo.getData()), GoodsBox.class);
        if (StrUtil.isEmpty(goodsBox.getBoxCode())) {
            throw new UtilException("货箱编码为空");
        }
        GoodsBox model = super.getOne(Wrappers.<GoodsBox>lambdaQuery().eq(GoodsBox::getBoxCode, goodsBox.getBoxCode()).last("limit 1"));
        if (model == null) {
            throw new UtilException("货箱不存在");
        }
        ParamInfo<BoxNew> paramInfo = new ParamInfo();
        BoxNew boxNew = new BoxNew();
        boxNew.setId(model.getId());
        boxNew.setBoxCode(model.getBoxCode());
        boxNew.setGoodsBoxSpecId(model.getGoodsBoxSpecId());
        boxNew.setCreateBy(model.getCreateBy());
        paramInfo.setData(boxNew);
        return paramInfo;
    }
}
